using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;
using Zsa.Emulation.Util;
using Zsa.Emulation.Config;

namespace Zsa.Emulation.Render
{
    public class NesMachineManager<THostForm> : IDisposable, IMachineHost
        where THostForm : HostForm, new()
    {
        #region Fields
        /// <summary>
        /// The nes machines.
        /// </summary>
        private List<NesMachineHost> _Devices = new List<NesMachineHost>();

        /// <summary>
        /// The host form.
        /// </summary>
        private THostForm _HostForm;

        /// <summary>
        /// True if quiting.
        /// </summary>
        private bool _ShouldQuit = false;

        /// <summary>
        /// True if should run.  This is for minimized, etc.
        /// </summary>
        private bool _ShouldRun = true;

        /// <summary>
        /// True if disposed.
        /// </summary>
        private bool _IsDisposed = false;
        #endregion Fields

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="T:DeviceHost&lt;THostForm&gt;"/> class.
        /// </summary>
        public NesMachineManager()
        {
        }

        /// <summary>
        /// Releases unmanaged resources and performs other cleanup operations before the
        /// <see cref="DeviceHost"/> is reclaimed by garbage collection.
        /// </summary>
        ~NesMachineManager()
        {
            Dispose();
        }
        #endregion Constructor

        #region Methods

        /// <summary>
        /// Starts the device host.
        /// </summary>
        public void Start()
        {
            // Create the host form.
            _HostForm = new THostForm();
            _HostForm.InternalHost = this;
            // Subscribe to the host forms closing events.
            _HostForm.FormClosed += new FormClosedEventHandler(HostForm_FormClosed);
            _HostForm.FormClosing += new FormClosingEventHandler(HostForm_FormClosing);
            // Show the form.
            _HostForm.Show();
        }

        /// <summary>
        /// Emulator run loop.
        /// </summary>
        public void Run()
        {
            // The index of the current device.
            int _CurrentDeviceIndex = 0;

            // The nes device.
            NesMachineHost _DeviceItem = null;

            while (!_ShouldQuit)
            {
                _ShouldRun = _Devices.Count > 0;
                // Check the should run flag.
                if (!_ShouldRun)
                {
                    // While should not be running process the 
                    // messaging queue and sleep.
                    while (!_ShouldRun)
                    {
                        // Check for message.
                        if (PeekMessage.HasMessage)
                        {
                            //PeekMessage.Run();
                            Application.DoEvents();
                        }
                        else
                        {
                            // No message then sleep.
                            Thread.Sleep(60);
                        }
                        _ShouldRun = _Devices.Count > 0;
                    }
                }
                else
                {
                    // Otherwise process any message if there are any.
                    //PeekMessage.Run();
                    if (PeekMessage.HasMessage)
                    {
                        //PeekMessage.Run();
                        Application.DoEvents();
                    }
                }

                try
                {
                    // Loop through devices.
                    for (_CurrentDeviceIndex = 0; _CurrentDeviceIndex < _Devices.Count; _CurrentDeviceIndex++)
                    {
                        _Devices[_CurrentDeviceIndex].Run();
                    }
                }
                catch (Exception excep)
                {
                    TraceLogger.WriteException(excep,"Exception in device host render loop !");
                    _Devices.RemoveAt(_CurrentDeviceIndex);
                }
            }
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            if (_IsDisposed)
            {
                return;
            }
            _IsDisposed = true;
            if (_HostForm != null)
            {
                try
                {
                    _HostForm.Dispose();
                }
                catch { }
                finally
                {
                    _HostForm = null;
                }
            }
            GC.SuppressFinalize(this);

        }


        /// <summary>
        /// Gets a nes machine with the default
        /// settings and no render attached.
        /// </summary>
        /// <returns></returns>
        public NesMachineHost CreateMachine()
        {
            return CreateMachine(NesConfigurationManager.Default);
        }

        /// <summary>
        /// Creates the machine.
        /// </summary>
        /// <param name="profile">The profile.</param>
        /// <returns></returns>
        public NesMachineHost CreateMachine(NesConfigurationProfile profile)
        {
            return CreateMachine(profile, null, MachineHostFlags.Default);
        }

        /// <summary>
        /// Creates the device.
        /// </summary>
        /// <param name="profile">The profile.</param>
        /// <param name="surfaceControl">The surface control.</param>
        /// <param name="flags">The flags.</param>
        /// <returns></returns>
        public NesMachineHost CreateMachine(NesConfigurationProfile profile, Control surfaceControl,
            MachineHostFlags flags)
        {
            // Create the host.
            NesMachineHost _Host = new NesMachineHost(profile, surfaceControl, flags);
            // Add to the list
            _Devices.Add(_Host);
            // Return the host
            return _Host;
        }
        #region Form Event Handlers
        /// <summary>
        /// Handles the FormClosed event of the HostForm control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.FormClosedEventArgs"/> instance containing the event data.</param>
        private void HostForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            _ShouldQuit = true;
        }

        /// <summary>
        /// Handles the FormClosing event of the HostForm control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.FormClosingEventArgs"/> instance containing the event data.</param>
        private void HostForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            // shutdown the emu, save settings here.
        }
        #endregion Form Event Handlers

        #endregion Methods

        #region Properties

        /// <summary>
        /// Gets the <see cref="Zsa.Emulation.NesDevice"/> at the specified index.
        /// </summary>
        /// <value></value>
        public NesMachineHost this[int index]
        {
            get
            {
                return _Devices[index];
            }
        }

        /// <summary>
        /// Gets a value indicating whether [should quit].
        /// </summary>
        /// <value><c>true</c> if [should quit]; otherwise, <c>false</c>.</value>
        public bool ShouldQuit
        {
            get
            {
                return _ShouldQuit;
            }
        }

        /// <summary>
        /// The hosted devices.
        /// </summary>
        /// <value></value>
        public IList<NesMachineHost> HostedDevices
        {
            get
            {
                return _Devices;
            }
        }
        #endregion Properties





    }
}
